{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "# Load environment variables from openai.env file\n",
    "load_dotenv(\"openai.env\")\n",
    "\n",
    "# Read the OPENAI_API_KEY from the environment\n",
    "api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "api_base = os.getenv(\"OPENAI_API_BASE\")\n",
    "os.environ[\"OPENAI_API_KEY\"] = api_key\n",
    "os.environ[\"OPENAI_API_BASE\"] = api_base"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = 'all'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# LCEL接口\n",
    "- 输入格式\n",
    "- 输出格式\n",
    "- 8种不同的接口方式\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(\n",
    "    model=\"gpt-3.5-turbo\",\n",
    ")\n",
    "prompt = ChatPromptTemplate.from_template(\"给我讲一个关于{topic}的笑话\")\n",
    "chain = prompt | model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "input schema"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'title': 'PromptInput',\n",
       " 'type': 'object',\n",
       " 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#prompt.\n",
    "chain.input_schema.schema()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'title': 'PromptInput',\n",
       " 'type': 'object',\n",
       " 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt.input_schema.schema()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'title': 'ChatOpenAIInput',\n",
       " 'anyOf': [{'type': 'string'},\n",
       "  {'$ref': '#/definitions/StringPromptValue'},\n",
       "  {'$ref': '#/definitions/ChatPromptValueConcrete'},\n",
       "  {'type': 'array',\n",
       "   'items': {'anyOf': [{'$ref': '#/definitions/AIMessage'},\n",
       "     {'$ref': '#/definitions/HumanMessage'},\n",
       "     {'$ref': '#/definitions/ChatMessage'},\n",
       "     {'$ref': '#/definitions/SystemMessage'},\n",
       "     {'$ref': '#/definitions/FunctionMessage'},\n",
       "     {'$ref': '#/definitions/ToolMessage'}]}}],\n",
       " 'definitions': {'StringPromptValue': {'title': 'StringPromptValue',\n",
       "   'description': 'String prompt value.',\n",
       "   'type': 'object',\n",
       "   'properties': {'text': {'title': 'Text', 'type': 'string'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'StringPromptValue',\n",
       "     'enum': ['StringPromptValue'],\n",
       "     'type': 'string'}},\n",
       "   'required': ['text']},\n",
       "  'AIMessage': {'title': 'AIMessage',\n",
       "   'description': 'Message from an AI.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'ai',\n",
       "     'enum': ['ai'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'},\n",
       "    'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},\n",
       "   'required': ['content']},\n",
       "  'HumanMessage': {'title': 'HumanMessage',\n",
       "   'description': 'Message from a human.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'human',\n",
       "     'enum': ['human'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'},\n",
       "    'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},\n",
       "   'required': ['content']},\n",
       "  'ChatMessage': {'title': 'ChatMessage',\n",
       "   'description': 'Message that can be assigned an arbitrary speaker (i.e. role).',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'chat',\n",
       "     'enum': ['chat'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'},\n",
       "    'role': {'title': 'Role', 'type': 'string'}},\n",
       "   'required': ['content', 'role']},\n",
       "  'SystemMessage': {'title': 'SystemMessage',\n",
       "   'description': 'Message for priming AI behavior, usually passed in as the first of a sequence\\nof input messages.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'system',\n",
       "     'enum': ['system'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'}},\n",
       "   'required': ['content']},\n",
       "  'FunctionMessage': {'title': 'FunctionMessage',\n",
       "   'description': 'Message for passing the result of executing a function back to a model.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'function',\n",
       "     'enum': ['function'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'}},\n",
       "   'required': ['content', 'name']},\n",
       "  'ToolMessage': {'title': 'ToolMessage',\n",
       "   'description': 'Message for passing the result of executing a tool back to a model.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'tool',\n",
       "     'enum': ['tool'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'},\n",
       "    'tool_call_id': {'title': 'Tool Call Id', 'type': 'string'}},\n",
       "   'required': ['content', 'tool_call_id']},\n",
       "  'ChatPromptValueConcrete': {'title': 'ChatPromptValueConcrete',\n",
       "   'description': 'Chat prompt value which explicitly lists out the message types it accepts.\\nFor use in external schemas.',\n",
       "   'type': 'object',\n",
       "   'properties': {'messages': {'title': 'Messages',\n",
       "     'type': 'array',\n",
       "     'items': {'anyOf': [{'$ref': '#/definitions/AIMessage'},\n",
       "       {'$ref': '#/definitions/HumanMessage'},\n",
       "       {'$ref': '#/definitions/ChatMessage'},\n",
       "       {'$ref': '#/definitions/SystemMessage'},\n",
       "       {'$ref': '#/definitions/FunctionMessage'},\n",
       "       {'$ref': '#/definitions/ToolMessage'}]}},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'ChatPromptValueConcrete',\n",
       "     'enum': ['ChatPromptValueConcrete'],\n",
       "     'type': 'string'}},\n",
       "   'required': ['messages']}}}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.input_schema.schema()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Output Schema"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'title': 'ChatOpenAIOutput',\n",
       " 'anyOf': [{'$ref': '#/definitions/AIMessage'},\n",
       "  {'$ref': '#/definitions/HumanMessage'},\n",
       "  {'$ref': '#/definitions/ChatMessage'},\n",
       "  {'$ref': '#/definitions/SystemMessage'},\n",
       "  {'$ref': '#/definitions/FunctionMessage'},\n",
       "  {'$ref': '#/definitions/ToolMessage'}],\n",
       " 'definitions': {'AIMessage': {'title': 'AIMessage',\n",
       "   'description': 'Message from an AI.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'ai',\n",
       "     'enum': ['ai'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'},\n",
       "    'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},\n",
       "   'required': ['content']},\n",
       "  'HumanMessage': {'title': 'HumanMessage',\n",
       "   'description': 'Message from a human.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'human',\n",
       "     'enum': ['human'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'},\n",
       "    'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},\n",
       "   'required': ['content']},\n",
       "  'ChatMessage': {'title': 'ChatMessage',\n",
       "   'description': 'Message that can be assigned an arbitrary speaker (i.e. role).',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'chat',\n",
       "     'enum': ['chat'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'},\n",
       "    'role': {'title': 'Role', 'type': 'string'}},\n",
       "   'required': ['content', 'role']},\n",
       "  'SystemMessage': {'title': 'SystemMessage',\n",
       "   'description': 'Message for priming AI behavior, usually passed in as the first of a sequence\\nof input messages.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'system',\n",
       "     'enum': ['system'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'}},\n",
       "   'required': ['content']},\n",
       "  'FunctionMessage': {'title': 'FunctionMessage',\n",
       "   'description': 'Message for passing the result of executing a function back to a model.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'function',\n",
       "     'enum': ['function'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'}},\n",
       "   'required': ['content', 'name']},\n",
       "  'ToolMessage': {'title': 'ToolMessage',\n",
       "   'description': 'Message for passing the result of executing a tool back to a model.',\n",
       "   'type': 'object',\n",
       "   'properties': {'content': {'title': 'Content',\n",
       "     'anyOf': [{'type': 'string'},\n",
       "      {'type': 'array',\n",
       "       'items': {'anyOf': [{'type': 'string'}, {'type': 'object'}]}}]},\n",
       "    'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n",
       "    'response_metadata': {'title': 'Response Metadata', 'type': 'object'},\n",
       "    'type': {'title': 'Type',\n",
       "     'default': 'tool',\n",
       "     'enum': ['tool'],\n",
       "     'type': 'string'},\n",
       "    'name': {'title': 'Name', 'type': 'string'},\n",
       "    'id': {'title': 'Id', 'type': 'string'},\n",
       "    'tool_call_id': {'title': 'Tool Call Id', 'type': 'string'}},\n",
       "   'required': ['content', 'tool_call_id']}}}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# The output schema of the chain is the output schema of its last part, in this case a ChatModel, which outputs a ChatMessage\n",
    "chain.output_schema.schema()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Stream（流式）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "为什么熊喜欢在树林里打篮球？\n",
      "\n",
      "因为他们喜欢熊篷！😄"
     ]
    }
   ],
   "source": [
    "for s in chain.stream({\"topic\": \"熊\"}):\n",
    "    print(s.content, end=\"\", flush=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Invoke"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='为什么熊不喜欢下雨天？\\n因为它会变成“湿熊”！😄🐻', response_metadata={'finish_reason': 'stop', 'logprobs': None})"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke({\"topic\": \"熊\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Batch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[AIMessage(content='为什么熊不喜欢冬天？\\n\\n因为它们的冰淇淋总是融化！哈哈哈！', response_metadata={'finish_reason': 'stop', 'logprobs': None}),\n",
       " AIMessage(content='为什么猫喜欢打猎？\\n因为他们喜欢尖叫！', response_metadata={'finish_reason': 'stop', 'logprobs': None})]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.batch([{\"topic\": \"熊\"}, {\"topic\": \"猫\"}])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[AIMessage(content='为什么熊不喜欢在雨天出门？\\n因为它怕变成“湿熊”！😄🐻', response_metadata={'finish_reason': 'stop', 'logprobs': None}),\n",
       " AIMessage(content='为什么猫喜欢在键盘上踩来踩去？\\n\\n因为它们喜欢按键！', response_metadata={'finish_reason': 'stop', 'logprobs': None}),\n",
       " AIMessage(content='当狗狗去看牙医时，它们会被问到：“你是不是每天都刷牙？”狗狗回答：“是的，但我还是用爪子擦地板。”哈哈哈。', response_metadata={'finish_reason': 'stop', 'logprobs': None})]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#max_concurrency控制并发数\n",
    "chain.batch([{\"topic\": \"熊\"}, {\"topic\": \"猫\"}, {\"topic\": \"狗\"}], config={\"max_concurrency\": 5})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Async Stream 异步"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "为什么女人喜欢购物？因为她们觉得买东西比减肥更能让自己开心！哈哈哈哈！"
     ]
    }
   ],
   "source": [
    "async for s in chain.astream({\"topic\": \"女人\"}):\n",
    "    print(s.content, end=\"\", flush=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Async Invoke"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='为什么男人喜欢开车？因为开车的时候，他们可以不用停下来问路。', response_metadata={'finish_reason': 'stop', 'logprobs': None})"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await chain.ainvoke({\"topic\": \"男人\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Async Batch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[AIMessage(content='为什么熊不喜欢雨天？\\n\\n因为它们怕变成“憨憨”！哈哈哈哈！', response_metadata={'finish_reason': 'stop', 'logprobs': None}),\n",
       " AIMessage(content='好的，这里有一个关于女人的笑话：\\n\\n为什么女人喜欢购物？\\n因为购物可以让她们忘记所有的烦恼，直到收到账单时又开始烦恼起来。😄', response_metadata={'finish_reason': 'stop', 'logprobs': None})]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "await chain.abatch([{\"topic\": \"熊\"},{\"topic\": \"女人\"}])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "异步获取中间步骤"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_community.vectorstores import FAISS\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.runnables import RunnablePassthrough\n",
    "from langchain_openai import OpenAIEmbeddings\n",
    "\n",
    "template = \"\"\"基于下面的上下文来回答问题:\n",
    "{context}\n",
    "\n",
    "Question: {question}\n",
    "\"\"\"\n",
    "prompt = ChatPromptTemplate.from_template(template)\n",
    "\n",
    "vectorstore = FAISS.from_texts(\n",
    "    [\"柯基犬是一种中型家庭宠物犬\"], embedding=OpenAIEmbeddings()\n",
    ")\n",
    "retriever = vectorstore.as_retriever()\n",
    "\n",
    "retrieval_chain = (\n",
    "    {\n",
    "        \"context\": retriever.with_config(run_name=\"Docs\"),\n",
    "        \"question\": RunnablePassthrough(),\n",
    "    }\n",
    "    | prompt\n",
    "    | model\n",
    "    | StrOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----------------------------------------\n",
      "RunLogPatch({'op': 'replace',\n",
      "  'path': '',\n",
      "  'value': {'final_output': None,\n",
      "            'id': '756a766b-029b-4026-86a4-0b04cf7bf52f',\n",
      "            'logs': {},\n",
      "            'name': 'RunnableSequence',\n",
      "            'streamed_output': [],\n",
      "            'type': 'chain'}})\n",
      "----------------------------------------\n",
      "RunLogPatch({'op': 'add',\n",
      "  'path': '/logs/Docs',\n",
      "  'value': {'end_time': None,\n",
      "            'final_output': None,\n",
      "            'id': '40e13b9f-893f-40e0-8cdf-5ccb45993a0f',\n",
      "            'metadata': {},\n",
      "            'name': 'Docs',\n",
      "            'start_time': '2024-03-14T09:47:23.960+00:00',\n",
      "            'streamed_output': [],\n",
      "            'streamed_output_str': [],\n",
      "            'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "            'type': 'retriever'}})\n",
      "----------------------------------------\n",
      "RunLogPatch({'op': 'add', 'path': '/logs/Docs/final_output', 'value': None},\n",
      " {'op': 'add',\n",
      "  'path': '/logs/Docs/end_time',\n",
      "  'value': '2024-03-14T09:47:24.678+00:00'})\n"
     ]
    },
    {
     "ename": "AuthenticationError",
     "evalue": "Error code: 401 - {'error': {'message': 'This API key is not authorized to access this model(`text-embedding-ada-002`) or the model you request does not exist. Please check or update your API key permissions, or check if the model name you requested is correct. (request id: 2024031409472452867036488463474)', 'type': 'upstream_error', 'param': '401', 'code': 'bad_response_status_code'}}",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAuthenticationError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[16], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m retrieval_chain\u001b[38;5;241m.\u001b[39mastream_log(\n\u001b[1;32m      2\u001b[0m     \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m柯基是什么?\u001b[39m\u001b[38;5;124m\"\u001b[39m, include_names\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDocs\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m      3\u001b[0m ):\n\u001b[1;32m      4\u001b[0m     \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m-\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m*\u001b[39m \u001b[38;5;241m40\u001b[39m)\n\u001b[1;32m      5\u001b[0m     \u001b[38;5;28mprint\u001b[39m(chunk)\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:683\u001b[0m, in \u001b[0;36mRunnable.astream_log\u001b[0;34m(self, input, config, diff, with_streamed_output_list, include_names, include_types, include_tags, exclude_names, exclude_types, exclude_tags, **kwargs)\u001b[0m\n\u001b[1;32m    669\u001b[0m stream \u001b[38;5;241m=\u001b[39m LogStreamCallbackHandler(\n\u001b[1;32m    670\u001b[0m     auto_close\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[1;32m    671\u001b[0m     include_names\u001b[38;5;241m=\u001b[39minclude_names,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    677\u001b[0m     _schema_format\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moriginal\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m    678\u001b[0m )\n\u001b[1;32m    680\u001b[0m \u001b[38;5;66;03m# Mypy isn't resolving the overloads here\u001b[39;00m\n\u001b[1;32m    681\u001b[0m \u001b[38;5;66;03m# Likely an issue b/c `self` is being passed through\u001b[39;00m\n\u001b[1;32m    682\u001b[0m \u001b[38;5;66;03m# and it's can't map it to Runnable[Input,Output]?\u001b[39;00m\n\u001b[0;32m--> 683\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m item \u001b[38;5;129;01min\u001b[39;00m _astream_log_implementation(  \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m    684\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m    685\u001b[0m     \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m    686\u001b[0m     config,\n\u001b[1;32m    687\u001b[0m     diff\u001b[38;5;241m=\u001b[39mdiff,\n\u001b[1;32m    688\u001b[0m     stream\u001b[38;5;241m=\u001b[39mstream,\n\u001b[1;32m    689\u001b[0m     with_streamed_output_list\u001b[38;5;241m=\u001b[39mwith_streamed_output_list,\n\u001b[1;32m    690\u001b[0m ):\n\u001b[1;32m    691\u001b[0m     \u001b[38;5;28;01myield\u001b[39;00m item\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/tracers/log_stream.py:616\u001b[0m, in \u001b[0;36m_astream_log_implementation\u001b[0;34m(runnable, input, config, stream, diff, with_streamed_output_list, **kwargs)\u001b[0m\n\u001b[1;32m    613\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m    614\u001b[0m     \u001b[38;5;66;03m# Wait for the runnable to finish, if not cancelled (eg. by break)\u001b[39;00m\n\u001b[1;32m    615\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 616\u001b[0m         \u001b[38;5;28;01mawait\u001b[39;00m task\n\u001b[1;32m    617\u001b[0m     \u001b[38;5;28;01mexcept\u001b[39;00m asyncio\u001b[38;5;241m.\u001b[39mCancelledError:\n\u001b[1;32m    618\u001b[0m         \u001b[38;5;28;01mpass\u001b[39;00m\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/tracers/log_stream.py:570\u001b[0m, in \u001b[0;36m_astream_log_implementation.<locals>.consume_astream\u001b[0;34m()\u001b[0m\n\u001b[1;32m    567\u001b[0m prev_final_output: Optional[Output] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m    568\u001b[0m final_output: Optional[Output] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m--> 570\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m runnable\u001b[38;5;241m.\u001b[39mastream(\u001b[38;5;28minput\u001b[39m, config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m    571\u001b[0m     prev_final_output \u001b[38;5;241m=\u001b[39m final_output\n\u001b[1;32m    572\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m final_output \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:2485\u001b[0m, in \u001b[0;36mRunnableSequence.astream\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m   2482\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minput_aiter\u001b[39m() \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m AsyncIterator[Input]:\n\u001b[1;32m   2483\u001b[0m     \u001b[38;5;28;01myield\u001b[39;00m \u001b[38;5;28minput\u001b[39m\n\u001b[0;32m-> 2485\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39matransform(input_aiter(), config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m   2486\u001b[0m     \u001b[38;5;28;01myield\u001b[39;00m chunk\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:2468\u001b[0m, in \u001b[0;36mRunnableSequence.atransform\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m   2462\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21matransform\u001b[39m(\n\u001b[1;32m   2463\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m   2464\u001b[0m     \u001b[38;5;28minput\u001b[39m: AsyncIterator[Input],\n\u001b[1;32m   2465\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m   2466\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Optional[Any],\n\u001b[1;32m   2467\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m AsyncIterator[Output]:\n\u001b[0;32m-> 2468\u001b[0m     \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_atransform_stream_with_config(\n\u001b[1;32m   2469\u001b[0m         \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m   2470\u001b[0m         \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_atransform,\n\u001b[1;32m   2471\u001b[0m         patch_config(config, run_name\u001b[38;5;241m=\u001b[39m(config \u001b[38;5;129;01mor\u001b[39;00m {})\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_name\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname),\n\u001b[1;32m   2472\u001b[0m         \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs,\n\u001b[1;32m   2473\u001b[0m     ):\n\u001b[1;32m   2474\u001b[0m         \u001b[38;5;28;01myield\u001b[39;00m chunk\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:1625\u001b[0m, in \u001b[0;36mRunnable._atransform_stream_with_config\u001b[0;34m(self, input, transformer, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m   1623\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[1;32m   1624\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m accepts_context(asyncio\u001b[38;5;241m.\u001b[39mcreate_task):\n\u001b[0;32m-> 1625\u001b[0m         chunk: Output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio\u001b[38;5;241m.\u001b[39mcreate_task(  \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m   1626\u001b[0m             py_anext(iterator),  \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[1;32m   1627\u001b[0m             context\u001b[38;5;241m=\u001b[39mcontext,\n\u001b[1;32m   1628\u001b[0m         )\n\u001b[1;32m   1629\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m   1630\u001b[0m         chunk \u001b[38;5;241m=\u001b[39m cast(Output, \u001b[38;5;28;01mawait\u001b[39;00m py_anext(iterator))\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/tracers/log_stream.py:237\u001b[0m, in \u001b[0;36mLogStreamCallbackHandler.tap_output_aiter\u001b[0;34m(self, run_id, output)\u001b[0m\n\u001b[1;32m    233\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mtap_output_aiter\u001b[39m(\n\u001b[1;32m    234\u001b[0m     \u001b[38;5;28mself\u001b[39m, run_id: UUID, output: AsyncIterator[T]\n\u001b[1;32m    235\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m AsyncIterator[T]:\n\u001b[1;32m    236\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Tap an output async iterator to stream its values to the log.\"\"\"\u001b[39;00m\n\u001b[0;32m--> 237\u001b[0m     \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m output:\n\u001b[1;32m    238\u001b[0m         \u001b[38;5;66;03m# root run is handled in .astream_log()\u001b[39;00m\n\u001b[1;32m    239\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m run_id \u001b[38;5;241m!=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mroot_id:\n\u001b[1;32m    240\u001b[0m             \u001b[38;5;66;03m# if we can't find the run silently ignore\u001b[39;00m\n\u001b[1;32m    241\u001b[0m             \u001b[38;5;66;03m# eg. because this run wasn't included in the log\u001b[39;00m\n\u001b[1;32m    242\u001b[0m             \u001b[38;5;28;01mif\u001b[39;00m key \u001b[38;5;241m:=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_key_map_by_run_id\u001b[38;5;241m.\u001b[39mget(run_id):\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:2438\u001b[0m, in \u001b[0;36mRunnableSequence._atransform\u001b[0;34m(self, input, run_manager, config)\u001b[0m\n\u001b[1;32m   2430\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m step \u001b[38;5;129;01min\u001b[39;00m steps:\n\u001b[1;32m   2431\u001b[0m     final_pipeline \u001b[38;5;241m=\u001b[39m step\u001b[38;5;241m.\u001b[39matransform(\n\u001b[1;32m   2432\u001b[0m         final_pipeline,\n\u001b[1;32m   2433\u001b[0m         patch_config(\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m   2436\u001b[0m         ),\n\u001b[1;32m   2437\u001b[0m     )\n\u001b[0;32m-> 2438\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m output \u001b[38;5;129;01min\u001b[39;00m final_pipeline:\n\u001b[1;32m   2439\u001b[0m     \u001b[38;5;28;01myield\u001b[39;00m output\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/output_parsers/transform.py:60\u001b[0m, in \u001b[0;36mBaseTransformOutputParser.atransform\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m     54\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21matransform\u001b[39m(\n\u001b[1;32m     55\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m     56\u001b[0m     \u001b[38;5;28minput\u001b[39m: AsyncIterator[Union[\u001b[38;5;28mstr\u001b[39m, BaseMessage]],\n\u001b[1;32m     57\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m     58\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m     59\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m AsyncIterator[T]:\n\u001b[0;32m---> 60\u001b[0m     \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_atransform_stream_with_config(\n\u001b[1;32m     61\u001b[0m         \u001b[38;5;28minput\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_atransform, config, run_type\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparser\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m     62\u001b[0m     ):\n\u001b[1;32m     63\u001b[0m         \u001b[38;5;28;01myield\u001b[39;00m chunk\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:1590\u001b[0m, in \u001b[0;36mRunnable._atransform_stream_with_config\u001b[0;34m(self, input, transformer, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m   1588\u001b[0m input_for_tracing, input_for_transform \u001b[38;5;241m=\u001b[39m atee(\u001b[38;5;28minput\u001b[39m, \u001b[38;5;241m2\u001b[39m)\n\u001b[1;32m   1589\u001b[0m \u001b[38;5;66;03m# Start the input iterator to ensure the input runnable starts before this one\u001b[39;00m\n\u001b[0;32m-> 1590\u001b[0m final_input: Optional[Input] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m py_anext(input_for_tracing, \u001b[38;5;28;01mNone\u001b[39;00m)\n\u001b[1;32m   1591\u001b[0m final_input_supported \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m   1592\u001b[0m final_output: Optional[Output] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/utils/aiter.py:62\u001b[0m, in \u001b[0;36mpy_anext.<locals>.anext_impl\u001b[0;34m()\u001b[0m\n\u001b[1;32m     55\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21manext_impl\u001b[39m() \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Union[T, Any]:\n\u001b[1;32m     56\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m     57\u001b[0m         \u001b[38;5;66;03m# The C code is way more low-level than this, as it implements\u001b[39;00m\n\u001b[1;32m     58\u001b[0m         \u001b[38;5;66;03m# all methods of the iterator protocol. In this implementation\u001b[39;00m\n\u001b[1;32m     59\u001b[0m         \u001b[38;5;66;03m# we're relying on higher-level coroutine concepts, but that's\u001b[39;00m\n\u001b[1;32m     60\u001b[0m         \u001b[38;5;66;03m# exactly what we want -- crosstest pure-Python high-level\u001b[39;00m\n\u001b[1;32m     61\u001b[0m         \u001b[38;5;66;03m# implementation and low-level C anext() iterators.\u001b[39;00m\n\u001b[0;32m---> 62\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;21m__anext__\u001b[39m(iterator)\n\u001b[1;32m     63\u001b[0m     \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mStopAsyncIteration\u001b[39;00m:\n\u001b[1;32m     64\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m default\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/utils/aiter.py:97\u001b[0m, in \u001b[0;36mtee_peer\u001b[0;34m(iterator, buffer, peers, lock)\u001b[0m\n\u001b[1;32m     95\u001b[0m     \u001b[38;5;28;01mcontinue\u001b[39;00m\n\u001b[1;32m     96\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 97\u001b[0m     item \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m iterator\u001b[38;5;241m.\u001b[39m\u001b[38;5;21m__anext__\u001b[39m()\n\u001b[1;32m     98\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mStopAsyncIteration\u001b[39;00m:\n\u001b[1;32m     99\u001b[0m     \u001b[38;5;28;01mbreak\u001b[39;00m\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:1084\u001b[0m, in \u001b[0;36mRunnable.atransform\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m   1081\u001b[0m final: Input\n\u001b[1;32m   1082\u001b[0m got_first_val \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[0;32m-> 1084\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28minput\u001b[39m:\n\u001b[1;32m   1085\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m got_first_val:\n\u001b[1;32m   1086\u001b[0m         final \u001b[38;5;241m=\u001b[39m _adapt_first_streaming_chunk(chunk)  \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:1084\u001b[0m, in \u001b[0;36mRunnable.atransform\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m   1081\u001b[0m final: Input\n\u001b[1;32m   1082\u001b[0m got_first_val \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[0;32m-> 1084\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28minput\u001b[39m:\n\u001b[1;32m   1085\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m got_first_val:\n\u001b[1;32m   1086\u001b[0m         final \u001b[38;5;241m=\u001b[39m _adapt_first_streaming_chunk(chunk)  \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:2896\u001b[0m, in \u001b[0;36mRunnableParallel.atransform\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m   2890\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21matransform\u001b[39m(\n\u001b[1;32m   2891\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m   2892\u001b[0m     \u001b[38;5;28minput\u001b[39m: AsyncIterator[Input],\n\u001b[1;32m   2893\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m   2894\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m   2895\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m AsyncIterator[Dict[\u001b[38;5;28mstr\u001b[39m, Any]]:\n\u001b[0;32m-> 2896\u001b[0m     \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_atransform_stream_with_config(\n\u001b[1;32m   2897\u001b[0m         \u001b[38;5;28minput\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_atransform, config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs\n\u001b[1;32m   2898\u001b[0m     ):\n\u001b[1;32m   2899\u001b[0m         \u001b[38;5;28;01myield\u001b[39;00m chunk\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:1625\u001b[0m, in \u001b[0;36mRunnable._atransform_stream_with_config\u001b[0;34m(self, input, transformer, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m   1623\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[1;32m   1624\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m accepts_context(asyncio\u001b[38;5;241m.\u001b[39mcreate_task):\n\u001b[0;32m-> 1625\u001b[0m         chunk: Output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m asyncio\u001b[38;5;241m.\u001b[39mcreate_task(  \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m   1626\u001b[0m             py_anext(iterator),  \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[1;32m   1627\u001b[0m             context\u001b[38;5;241m=\u001b[39mcontext,\n\u001b[1;32m   1628\u001b[0m         )\n\u001b[1;32m   1629\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m   1630\u001b[0m         chunk \u001b[38;5;241m=\u001b[39m cast(Output, \u001b[38;5;28;01mawait\u001b[39;00m py_anext(iterator))\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/tracers/log_stream.py:237\u001b[0m, in \u001b[0;36mLogStreamCallbackHandler.tap_output_aiter\u001b[0;34m(self, run_id, output)\u001b[0m\n\u001b[1;32m    233\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mtap_output_aiter\u001b[39m(\n\u001b[1;32m    234\u001b[0m     \u001b[38;5;28mself\u001b[39m, run_id: UUID, output: AsyncIterator[T]\n\u001b[1;32m    235\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m AsyncIterator[T]:\n\u001b[1;32m    236\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Tap an output async iterator to stream its values to the log.\"\"\"\u001b[39;00m\n\u001b[0;32m--> 237\u001b[0m     \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m chunk \u001b[38;5;129;01min\u001b[39;00m output:\n\u001b[1;32m    238\u001b[0m         \u001b[38;5;66;03m# root run is handled in .astream_log()\u001b[39;00m\n\u001b[1;32m    239\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m run_id \u001b[38;5;241m!=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mroot_id:\n\u001b[1;32m    240\u001b[0m             \u001b[38;5;66;03m# if we can't find the run silently ignore\u001b[39;00m\n\u001b[1;32m    241\u001b[0m             \u001b[38;5;66;03m# eg. because this run wasn't included in the log\u001b[39;00m\n\u001b[1;32m    242\u001b[0m             \u001b[38;5;28;01mif\u001b[39;00m key \u001b[38;5;241m:=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_key_map_by_run_id\u001b[38;5;241m.\u001b[39mget(run_id):\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:2883\u001b[0m, in \u001b[0;36mRunnableParallel._atransform\u001b[0;34m(self, input, run_manager, config)\u001b[0m\n\u001b[1;32m   2881\u001b[0m (step_name, generator) \u001b[38;5;241m=\u001b[39m tasks\u001b[38;5;241m.\u001b[39mpop(task)\n\u001b[1;32m   2882\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 2883\u001b[0m     chunk \u001b[38;5;241m=\u001b[39m AddableDict({step_name: \u001b[43mtask\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresult\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m})\n\u001b[1;32m   2884\u001b[0m     \u001b[38;5;28;01myield\u001b[39;00m chunk\n\u001b[1;32m   2885\u001b[0m     new_task \u001b[38;5;241m=\u001b[39m asyncio\u001b[38;5;241m.\u001b[39mcreate_task(get_next_chunk(generator))\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:2866\u001b[0m, in \u001b[0;36mRunnableParallel._atransform.<locals>.get_next_chunk\u001b[0;34m(generator)\u001b[0m\n\u001b[1;32m   2865\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_next_chunk\u001b[39m(generator: AsyncIterator) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Optional[Output]:\n\u001b[0;32m-> 2866\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m py_anext(generator)\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:4206\u001b[0m, in \u001b[0;36mRunnableBindingBase.atransform\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m   4200\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21matransform\u001b[39m(\n\u001b[1;32m   4201\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m   4202\u001b[0m     \u001b[38;5;28minput\u001b[39m: AsyncIterator[Input],\n\u001b[1;32m   4203\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m   4204\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m   4205\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m AsyncIterator[Output]:\n\u001b[0;32m-> 4206\u001b[0m     \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m item \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbound\u001b[38;5;241m.\u001b[39matransform(\n\u001b[1;32m   4207\u001b[0m         \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m   4208\u001b[0m         \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_merge_configs(config),\n\u001b[1;32m   4209\u001b[0m         \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m{\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mkwargs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs},\n\u001b[1;32m   4210\u001b[0m     ):\n\u001b[1;32m   4211\u001b[0m         \u001b[38;5;28;01myield\u001b[39;00m item\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:1101\u001b[0m, in \u001b[0;36mRunnable.atransform\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m   1094\u001b[0m             \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\n\u001b[1;32m   1095\u001b[0m                 \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFailed while trying to add together \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m   1096\u001b[0m                 \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtype \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(final)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(chunk)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m   1097\u001b[0m                 \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThese types should be addable for atransform to work.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m   1098\u001b[0m             )\n\u001b[1;32m   1100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m got_first_val:\n\u001b[0;32m-> 1101\u001b[0m     \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mfor\u001b[39;00m output \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mastream(final, config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m   1102\u001b[0m         \u001b[38;5;28;01myield\u001b[39;00m output\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/runnables/base.py:589\u001b[0m, in \u001b[0;36mRunnable.astream\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m    579\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mastream\u001b[39m(\n\u001b[1;32m    580\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m    581\u001b[0m     \u001b[38;5;28minput\u001b[39m: Input,\n\u001b[1;32m    582\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m    583\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Optional[Any],\n\u001b[1;32m    584\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m AsyncIterator[Output]:\n\u001b[1;32m    585\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m    586\u001b[0m \u001b[38;5;124;03m    Default implementation of astream, which calls ainvoke.\u001b[39;00m\n\u001b[1;32m    587\u001b[0m \u001b[38;5;124;03m    Subclasses should override this method if they support streaming output.\u001b[39;00m\n\u001b[1;32m    588\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[0;32m--> 589\u001b[0m     \u001b[38;5;28;01myield\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mainvoke(\u001b[38;5;28minput\u001b[39m, config, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/retrievers.py:157\u001b[0m, in \u001b[0;36mBaseRetriever.ainvoke\u001b[0;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[1;32m    150\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mainvoke\u001b[39m(\n\u001b[1;32m    151\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m    152\u001b[0m     \u001b[38;5;28minput\u001b[39m: \u001b[38;5;28mstr\u001b[39m,\n\u001b[1;32m    153\u001b[0m     config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m    154\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m    155\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[Document]:\n\u001b[1;32m    156\u001b[0m     config \u001b[38;5;241m=\u001b[39m ensure_config(config)\n\u001b[0;32m--> 157\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39maget_relevant_documents(\n\u001b[1;32m    158\u001b[0m         \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m    159\u001b[0m         callbacks\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcallbacks\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m    160\u001b[0m         tags\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtags\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m    161\u001b[0m         metadata\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetadata\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m    162\u001b[0m         run_name\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_name\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m    163\u001b[0m         \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs,\n\u001b[1;32m    164\u001b[0m     )\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/retrievers.py:300\u001b[0m, in \u001b[0;36mBaseRetriever.aget_relevant_documents\u001b[0;34m(self, query, callbacks, tags, metadata, run_name, **kwargs)\u001b[0m\n\u001b[1;32m    298\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m    299\u001b[0m     \u001b[38;5;28;01mawait\u001b[39;00m run_manager\u001b[38;5;241m.\u001b[39mon_retriever_error(e)\n\u001b[0;32m--> 300\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m e\n\u001b[1;32m    301\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    302\u001b[0m     \u001b[38;5;28;01mawait\u001b[39;00m run_manager\u001b[38;5;241m.\u001b[39mon_retriever_end(\n\u001b[1;32m    303\u001b[0m         result,\n\u001b[1;32m    304\u001b[0m     )\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/retrievers.py:293\u001b[0m, in \u001b[0;36mBaseRetriever.aget_relevant_documents\u001b[0;34m(self, query, callbacks, tags, metadata, run_name, **kwargs)\u001b[0m\n\u001b[1;32m    291\u001b[0m _kwargs \u001b[38;5;241m=\u001b[39m kwargs \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_expects_other_args \u001b[38;5;28;01melse\u001b[39;00m {}\n\u001b[1;32m    292\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_new_arg_supported:\n\u001b[0;32m--> 293\u001b[0m     result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_aget_relevant_documents(\n\u001b[1;32m    294\u001b[0m         query, run_manager\u001b[38;5;241m=\u001b[39mrun_manager, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m_kwargs\n\u001b[1;32m    295\u001b[0m     )\n\u001b[1;32m    296\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    297\u001b[0m     result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_aget_relevant_documents(query, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m_kwargs)\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_core/vectorstores.py:694\u001b[0m, in \u001b[0;36mVectorStoreRetriever._aget_relevant_documents\u001b[0;34m(self, query, run_manager)\u001b[0m\n\u001b[1;32m    690\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_aget_relevant_documents\u001b[39m(\n\u001b[1;32m    691\u001b[0m     \u001b[38;5;28mself\u001b[39m, query: \u001b[38;5;28mstr\u001b[39m, \u001b[38;5;241m*\u001b[39m, run_manager: AsyncCallbackManagerForRetrieverRun\n\u001b[1;32m    692\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[Document]:\n\u001b[1;32m    693\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msearch_type \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msimilarity\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[0;32m--> 694\u001b[0m         docs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mvectorstore\u001b[38;5;241m.\u001b[39masimilarity_search(\n\u001b[1;32m    695\u001b[0m             query, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msearch_kwargs\n\u001b[1;32m    696\u001b[0m         )\n\u001b[1;32m    697\u001b[0m     \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msearch_type \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msimilarity_score_threshold\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m    698\u001b[0m         docs_and_similarities \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m    699\u001b[0m             \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mvectorstore\u001b[38;5;241m.\u001b[39masimilarity_search_with_relevance_scores(\n\u001b[1;32m    700\u001b[0m                 query, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msearch_kwargs\n\u001b[1;32m    701\u001b[0m             )\n\u001b[1;32m    702\u001b[0m         )\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_community/vectorstores/faiss.py:555\u001b[0m, in \u001b[0;36mFAISS.asimilarity_search\u001b[0;34m(self, query, k, filter, fetch_k, **kwargs)\u001b[0m\n\u001b[1;32m    535\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21masimilarity_search\u001b[39m(\n\u001b[1;32m    536\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m    537\u001b[0m     query: \u001b[38;5;28mstr\u001b[39m,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    541\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m    542\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[Document]:\n\u001b[1;32m    543\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Return docs most similar to query asynchronously.\u001b[39;00m\n\u001b[1;32m    544\u001b[0m \n\u001b[1;32m    545\u001b[0m \u001b[38;5;124;03m    Args:\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    553\u001b[0m \u001b[38;5;124;03m        List of Documents most similar to the query.\u001b[39;00m\n\u001b[1;32m    554\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[0;32m--> 555\u001b[0m     docs_and_scores \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39masimilarity_search_with_score(\n\u001b[1;32m    556\u001b[0m         query, k, \u001b[38;5;28mfilter\u001b[39m\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mfilter\u001b[39m, fetch_k\u001b[38;5;241m=\u001b[39mfetch_k, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs\n\u001b[1;32m    557\u001b[0m     )\n\u001b[1;32m    558\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m [doc \u001b[38;5;28;01mfor\u001b[39;00m doc, _ \u001b[38;5;129;01min\u001b[39;00m docs_and_scores]\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_community/vectorstores/faiss.py:436\u001b[0m, in \u001b[0;36mFAISS.asimilarity_search_with_score\u001b[0;34m(self, query, k, filter, fetch_k, **kwargs)\u001b[0m\n\u001b[1;32m    412\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21masimilarity_search_with_score\u001b[39m(\n\u001b[1;32m    413\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m    414\u001b[0m     query: \u001b[38;5;28mstr\u001b[39m,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    418\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m    419\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[Tuple[Document, \u001b[38;5;28mfloat\u001b[39m]]:\n\u001b[1;32m    420\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Return docs most similar to query asynchronously.\u001b[39;00m\n\u001b[1;32m    421\u001b[0m \n\u001b[1;32m    422\u001b[0m \u001b[38;5;124;03m    Args:\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    434\u001b[0m \u001b[38;5;124;03m        L2 distance in float. Lower score represents more similarity.\u001b[39;00m\n\u001b[1;32m    435\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[0;32m--> 436\u001b[0m     embedding \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_aembed_query(query)\n\u001b[1;32m    437\u001b[0m     docs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39masimilarity_search_with_score_by_vector(\n\u001b[1;32m    438\u001b[0m         embedding,\n\u001b[1;32m    439\u001b[0m         k,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    442\u001b[0m         \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs,\n\u001b[1;32m    443\u001b[0m     )\n\u001b[1;32m    444\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m docs\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_community/vectorstores/faiss.py:160\u001b[0m, in \u001b[0;36mFAISS._aembed_query\u001b[0;34m(self, text)\u001b[0m\n\u001b[1;32m    158\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_aembed_query\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[\u001b[38;5;28mfloat\u001b[39m]:\n\u001b[1;32m    159\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39membedding_function, Embeddings):\n\u001b[0;32m--> 160\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39membedding_function\u001b[38;5;241m.\u001b[39maembed_query(text)\n\u001b[1;32m    161\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    162\u001b[0m         \u001b[38;5;66;03m# return await self.embedding_function(text)\u001b[39;00m\n\u001b[1;32m    163\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\n\u001b[1;32m    164\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m`embedding_function` is expected to be an Embeddings object, support \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    165\u001b[0m             \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfor passing in a function will soon be removed.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    166\u001b[0m         )\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_openai/embeddings/base.py:548\u001b[0m, in \u001b[0;36mOpenAIEmbeddings.aembed_query\u001b[0;34m(self, text)\u001b[0m\n\u001b[1;32m    539\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21maembed_query\u001b[39m(\u001b[38;5;28mself\u001b[39m, text: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m List[\u001b[38;5;28mfloat\u001b[39m]:\n\u001b[1;32m    540\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Call out to OpenAI's embedding endpoint async for embedding query text.\u001b[39;00m\n\u001b[1;32m    541\u001b[0m \n\u001b[1;32m    542\u001b[0m \u001b[38;5;124;03m    Args:\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    546\u001b[0m \u001b[38;5;124;03m        Embedding for the text.\u001b[39;00m\n\u001b[1;32m    547\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[0;32m--> 548\u001b[0m     embeddings \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39maembed_documents([text])\n\u001b[1;32m    549\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m embeddings[\u001b[38;5;241m0\u001b[39m]\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_openai/embeddings/base.py:526\u001b[0m, in \u001b[0;36mOpenAIEmbeddings.aembed_documents\u001b[0;34m(self, texts, chunk_size)\u001b[0m\n\u001b[1;32m    523\u001b[0m \u001b[38;5;66;03m# NOTE: to keep things simple, we assume the list may contain texts longer\u001b[39;00m\n\u001b[1;32m    524\u001b[0m \u001b[38;5;66;03m#       than the maximum context and use length-safe embedding function.\u001b[39;00m\n\u001b[1;32m    525\u001b[0m engine \u001b[38;5;241m=\u001b[39m cast(\u001b[38;5;28mstr\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdeployment)\n\u001b[0;32m--> 526\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_aget_len_safe_embeddings(texts, engine\u001b[38;5;241m=\u001b[39mengine)\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/langchain_openai/embeddings/base.py:449\u001b[0m, in \u001b[0;36mOpenAIEmbeddings._aget_len_safe_embeddings\u001b[0;34m(self, texts, engine, chunk_size)\u001b[0m\n\u001b[1;32m    447\u001b[0m _chunk_size \u001b[38;5;241m=\u001b[39m chunk_size \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mchunk_size\n\u001b[1;32m    448\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[38;5;241m0\u001b[39m, \u001b[38;5;28mlen\u001b[39m(tokens), _chunk_size):\n\u001b[0;32m--> 449\u001b[0m     response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39masync_client\u001b[38;5;241m.\u001b[39mcreate(\n\u001b[1;32m    450\u001b[0m         \u001b[38;5;28minput\u001b[39m\u001b[38;5;241m=\u001b[39mtokens[i : i \u001b[38;5;241m+\u001b[39m _chunk_size], \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_invocation_params\n\u001b[1;32m    451\u001b[0m     )\n\u001b[1;32m    453\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(response, \u001b[38;5;28mdict\u001b[39m):\n\u001b[1;32m    454\u001b[0m         response \u001b[38;5;241m=\u001b[39m response\u001b[38;5;241m.\u001b[39mmodel_dump()\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/openai/resources/embeddings.py:214\u001b[0m, in \u001b[0;36mAsyncEmbeddings.create\u001b[0;34m(self, input, model, dimensions, encoding_format, user, extra_headers, extra_query, extra_body, timeout)\u001b[0m\n\u001b[1;32m    208\u001b[0m         embedding\u001b[38;5;241m.\u001b[39membedding \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mfrombuffer(  \u001b[38;5;66;03m# type: ignore[no-untyped-call]\u001b[39;00m\n\u001b[1;32m    209\u001b[0m             base64\u001b[38;5;241m.\u001b[39mb64decode(data), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfloat32\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    210\u001b[0m         )\u001b[38;5;241m.\u001b[39mtolist()\n\u001b[1;32m    212\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m obj\n\u001b[0;32m--> 214\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_post(\n\u001b[1;32m    215\u001b[0m     \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m/embeddings\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m    216\u001b[0m     body\u001b[38;5;241m=\u001b[39mmaybe_transform(params, embedding_create_params\u001b[38;5;241m.\u001b[39mEmbeddingCreateParams),\n\u001b[1;32m    217\u001b[0m     options\u001b[38;5;241m=\u001b[39mmake_request_options(\n\u001b[1;32m    218\u001b[0m         extra_headers\u001b[38;5;241m=\u001b[39mextra_headers,\n\u001b[1;32m    219\u001b[0m         extra_query\u001b[38;5;241m=\u001b[39mextra_query,\n\u001b[1;32m    220\u001b[0m         extra_body\u001b[38;5;241m=\u001b[39mextra_body,\n\u001b[1;32m    221\u001b[0m         timeout\u001b[38;5;241m=\u001b[39mtimeout,\n\u001b[1;32m    222\u001b[0m         post_parser\u001b[38;5;241m=\u001b[39mparser,\n\u001b[1;32m    223\u001b[0m     ),\n\u001b[1;32m    224\u001b[0m     cast_to\u001b[38;5;241m=\u001b[39mCreateEmbeddingResponse,\n\u001b[1;32m    225\u001b[0m )\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/openai/_base_client.py:1738\u001b[0m, in \u001b[0;36mAsyncAPIClient.post\u001b[0;34m(self, path, cast_to, body, files, options, stream, stream_cls)\u001b[0m\n\u001b[1;32m   1724\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpost\u001b[39m(\n\u001b[1;32m   1725\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m   1726\u001b[0m     path: \u001b[38;5;28mstr\u001b[39m,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m   1733\u001b[0m     stream_cls: \u001b[38;5;28mtype\u001b[39m[_AsyncStreamT] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m   1734\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ResponseT \u001b[38;5;241m|\u001b[39m _AsyncStreamT:\n\u001b[1;32m   1735\u001b[0m     opts \u001b[38;5;241m=\u001b[39m FinalRequestOptions\u001b[38;5;241m.\u001b[39mconstruct(\n\u001b[1;32m   1736\u001b[0m         method\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpost\u001b[39m\u001b[38;5;124m\"\u001b[39m, url\u001b[38;5;241m=\u001b[39mpath, json_data\u001b[38;5;241m=\u001b[39mbody, files\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mawait\u001b[39;00m async_to_httpx_files(files), \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39moptions\n\u001b[1;32m   1737\u001b[0m     )\n\u001b[0;32m-> 1738\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrequest(cast_to, opts, stream\u001b[38;5;241m=\u001b[39mstream, stream_cls\u001b[38;5;241m=\u001b[39mstream_cls)\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/openai/_base_client.py:1441\u001b[0m, in \u001b[0;36mAsyncAPIClient.request\u001b[0;34m(self, cast_to, options, stream, stream_cls, remaining_retries)\u001b[0m\n\u001b[1;32m   1432\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mrequest\u001b[39m(\n\u001b[1;32m   1433\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m   1434\u001b[0m     cast_to: Type[ResponseT],\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m   1439\u001b[0m     remaining_retries: Optional[\u001b[38;5;28mint\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m   1440\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ResponseT \u001b[38;5;241m|\u001b[39m _AsyncStreamT:\n\u001b[0;32m-> 1441\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_request(\n\u001b[1;32m   1442\u001b[0m         cast_to\u001b[38;5;241m=\u001b[39mcast_to,\n\u001b[1;32m   1443\u001b[0m         options\u001b[38;5;241m=\u001b[39moptions,\n\u001b[1;32m   1444\u001b[0m         stream\u001b[38;5;241m=\u001b[39mstream,\n\u001b[1;32m   1445\u001b[0m         stream_cls\u001b[38;5;241m=\u001b[39mstream_cls,\n\u001b[1;32m   1446\u001b[0m         remaining_retries\u001b[38;5;241m=\u001b[39mremaining_retries,\n\u001b[1;32m   1447\u001b[0m     )\n",
      "File \u001b[0;32m~/.pyenv/versions/3.10.12/envs/langchains/lib/python3.11/site-packages/openai/_base_client.py:1532\u001b[0m, in \u001b[0;36mAsyncAPIClient._request\u001b[0;34m(self, cast_to, options, stream, stream_cls, remaining_retries)\u001b[0m\n\u001b[1;32m   1529\u001b[0m         \u001b[38;5;28;01mawait\u001b[39;00m err\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39maread()\n\u001b[1;32m   1531\u001b[0m     log\u001b[38;5;241m.\u001b[39mdebug(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRe-raising status error\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m-> 1532\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_make_status_error_from_response(err\u001b[38;5;241m.\u001b[39mresponse) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m   1534\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;01mawait\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_response(\n\u001b[1;32m   1535\u001b[0m     cast_to\u001b[38;5;241m=\u001b[39mcast_to,\n\u001b[1;32m   1536\u001b[0m     options\u001b[38;5;241m=\u001b[39moptions,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m   1539\u001b[0m     stream_cls\u001b[38;5;241m=\u001b[39mstream_cls,\n\u001b[1;32m   1540\u001b[0m )\n",
      "\u001b[0;31mAuthenticationError\u001b[0m: Error code: 401 - {'error': {'message': 'This API key is not authorized to access this model(`text-embedding-ada-002`) or the model you request does not exist. Please check or update your API key permissions, or check if the model name you requested is correct. (request id: 2024031409472452867036488463474)', 'type': 'upstream_error', 'param': '401', 'code': 'bad_response_status_code'}}"
     ]
    }
   ],
   "source": [
    "async for chunk in retrieval_chain.astream_log(\n",
    "    \"柯基是什么?\", include_names=[\"Docs\"]\n",
    "):\n",
    "    print(\"-\" * 40)\n",
    "    print(chunk)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "只看状态值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': None,\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': [],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': None,\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': None,\n",
      "                   'final_output': None,\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': [],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': None,\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': [],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': [''],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是', '一'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是', '一', '种'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是', '一', '种', '中'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中型',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是', '一', '种', '中', '型'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中型家',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是', '一', '种', '中', '型', '家'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中型家庭',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是', '一', '种', '中', '型', '家', '庭'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中型家庭宠',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是', '一', '种', '中', '型', '家', '庭', '宠'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中型家庭宠物',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['', '柯', '基', '是', '一', '种', '中', '型', '家', '庭', '宠', '物'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中型家庭宠物犬',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['',\n",
      "                     '柯',\n",
      "                     '基',\n",
      "                     '是',\n",
      "                     '一',\n",
      "                     '种',\n",
      "                     '中',\n",
      "                     '型',\n",
      "                     '家',\n",
      "                     '庭',\n",
      "                     '宠',\n",
      "                     '物',\n",
      "                     '犬'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中型家庭宠物犬。',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['',\n",
      "                     '柯',\n",
      "                     '基',\n",
      "                     '是',\n",
      "                     '一',\n",
      "                     '种',\n",
      "                     '中',\n",
      "                     '型',\n",
      "                     '家',\n",
      "                     '庭',\n",
      "                     '宠',\n",
      "                     '物',\n",
      "                     '犬',\n",
      "                     '。'],\n",
      " 'type': 'chain'})\n",
      "----------------------------------------------------------------------\n",
      "RunLog({'final_output': '柯基是一种中型家庭宠物犬。',\n",
      " 'id': '87926d3f-6e27-4c38-8e3b-5635eaa26a65',\n",
      " 'logs': {'Docs': {'end_time': '2024-02-16T03:25:40.534+00:00',\n",
      "                   'final_output': {'documents': [Document(page_content='柯基犬是一种中型家庭宠物犬')]},\n",
      "                   'id': '869cd627-f35a-4b75-8900-cad2cf826903',\n",
      "                   'metadata': {},\n",
      "                   'name': 'Docs',\n",
      "                   'start_time': '2024-02-16T03:25:39.457+00:00',\n",
      "                   'streamed_output': [],\n",
      "                   'streamed_output_str': [],\n",
      "                   'tags': ['map:key:context', 'FAISS', 'OpenAIEmbeddings'],\n",
      "                   'type': 'retriever'}},\n",
      " 'name': 'RunnableSequence',\n",
      " 'streamed_output': ['',\n",
      "                     '柯',\n",
      "                     '基',\n",
      "                     '是',\n",
      "                     '一',\n",
      "                     '种',\n",
      "                     '中',\n",
      "                     '型',\n",
      "                     '家',\n",
      "                     '庭',\n",
      "                     '宠',\n",
      "                     '物',\n",
      "                     '犬',\n",
      "                     '。',\n",
      "                     ''],\n",
      " 'type': 'chain'})\n"
     ]
    }
   ],
   "source": [
    "\n",
    "async for chunk in retrieval_chain.astream_log(\n",
    "    \"柯基是什么?\", include_names=[\"Docs\"], diff=False\n",
    "):\n",
    "    print(\"-\" * 70)\n",
    "    print(chunk)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "并行支持"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.runnables import RunnableParallel\n",
    "\n",
    "chain1 = ChatPromptTemplate.from_template(\"给我讲一个关于{topic}的笑话\") | model\n",
    "chain2 = (\n",
    "    ChatPromptTemplate.from_template(\"写两行关于{topic}的诗歌\")\n",
    "    | model\n",
    ")\n",
    "combined = RunnableParallel(joke=chain1, poem=chain2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 11.8 ms, sys: 9.75 ms, total: 21.6 ms\n",
      "Wall time: 8.46 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "AIMessage(content='好的，这是一个关于熊的笑话：\\n\\n有一天，一只小熊和一只大熊在森林里散步。突然，小熊看到了一只兔子正在忙碌地搬运胡萝卜。小熊很好奇，就走过去问兔子：“嘿，兔子，你在干什么呢？”\\n\\n兔子回答说：“我在准备过冬，搬运胡萝卜到我的洞里。”\\n\\n小熊顿时眼前一亮，说：“哇，这是个好主意！我也要去搬运食物存起来。”\\n\\n于是小熊和大熊一起去寻找食物。他们找到了一堆蜂蜜，想要把它们都搬回洞里。但是，由于蜂蜜太黏稠，小熊和大熊都被粘住了，无法动弹。\\n\\n这时，兔子从远处走过来，看到了这一幕，忍不住笑了起来。\\n\\n小熊生气地问：“兔子，你为什么笑？”\\n\\n兔子笑着说：“因为你们这样，看起来就像两只大糖葫芦！”\\n\\n听到这个，小熊和大熊也忍不住笑了起来，他们意识到自己的可笑模样。\\n\\n最终，兔子帮助小熊和大熊脱离了黏蜜的困境，三个朋友一起度过了愉快的日子。\\n\\n这个笑话希望能给你带来一些欢乐！')"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%time\n",
    "chain1.invoke({\"topic\": \"熊\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 15.5 ms, sys: 3.32 ms, total: 18.9 ms\n",
      "Wall time: 2.06 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "AIMessage(content='熊啊熊，森林中的王者，\\n毛茸茸，力量无穷，让人敬畏。')"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%time\n",
    "chain2.invoke({\"topic\": \"熊\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "并行执行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 20.1 ms, sys: 3.56 ms, total: 23.7 ms\n",
      "Wall time: 4.3 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'joke': AIMessage(content='好的，这里有一个关于熊的笑话：\\n\\n有一天，一只熊走进了一家餐馆。他坐在吧台前，对着酒保说：“我想要一杯……啊，忘了，我还是不要喝酒了。”酒保很好奇地问：“为什么？你是不是戒酒了？”熊摇了摇头，说：“不，其实是因为每次我喝酒后，我都会变得非常凶猛。”酒保好奇地问：“真的吗？那你是怎么知道的？”熊回答道：“因为每次我喝酒后，我都会去找猎人打架！”'),\n",
       " 'poem': AIMessage(content='大熊在山间踏步行，\\n森林中，威武似王者。')}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%time\n",
    "combined.invoke({\"topic\": \"熊\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "并行批处理，适用于大量生成"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 18.9 ms, sys: 3.17 ms, total: 22 ms\n",
      "Wall time: 3.56 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[AIMessage(content='当然，这是一个关于熊的笑话：\\n\\n有一天，一只熊走进了一家餐厅，坐在了一张桌子旁边。侍者走过来，询问熊说：“你想要点什么？” 熊说：“给我一份……鱼和…………苹果派。” 侍者看了一会儿，然后问道：“没问题，但是为什么你这么喜欢吃鱼和苹果派呢？” 熊回答说：“因为我是一只熊啊！”'),\n",
       " AIMessage(content='当猫遇到老鼠，老鼠问猫：\"你怕我吗？\"猫回答说：\"怕，怕你长得比我还丑！\"')]"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%time\n",
    "chain1.batch([{\"topic\": \"熊\"}, {\"topic\": \"猫\"}])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 19.9 ms, sys: 3.44 ms, total: 23.4 ms\n",
      "Wall time: 3.11 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[AIMessage(content='大熊展开双臂，迎风舞动如云蒸霞蔚。\\n巍峨身姿挺拔，守护山林万物生机绚。'),\n",
       " AIMessage(content='闲卧红砖上，猫儿慵懒眯眼眸。\\n蓬松尾巴飘飘扬，优雅姿态与我相伴。')]"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%time\n",
    "chain2.batch([{\"topic\": \"熊\"}, {\"topic\": \"猫\"}])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "并行执行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 35.7 ms, sys: 4.79 ms, total: 40.4 ms\n",
      "Wall time: 5.32 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[{'joke': AIMessage(content='当然！这是一个关于熊的笑话：\\n\\n有一天，一只小熊走进了一个酒吧。他走到吧台前，说：“请问，这里有熊吗？”吧台上的人们都愣住了，然后大笑起来。\\n\\n其中一个人回答道：“这里没有熊，只有人。”\\n\\n小熊感到非常失落，于是黯然离去。过了一段时间，小熊又回到了同一个酒吧。这次，他走到一个不同的吧台前，再次问道：“请问，这里有熊吗？”\\n\\n这次，人们没有大笑，而是纷纷低下头，不敢看小熊。小熊感到非常困惑，他问：“为什么你们这次不笑了？”\\n\\n吧台上的人们小声回答：“因为我们是熊。”\\n\\n希望这个笑话能让你开心！'),\n",
       "  'poem': AIMessage(content='森林深处，熊呼啸，\\n强壮的身躯，展露豪情。')},\n",
       " {'joke': AIMessage(content='当然！这是一个关于猫的笑话：\\n\\n有一天，一只猫走进了一家餐厅，他坐在了一张桌子旁边的椅子上。服务员非常惊讶地走过去，问道：“对不起，先生，我们这里不允许猫进来。”\\n\\n猫瞪大眼睛，回答说：“没关系，我只是想尝尝你们的鱼。”\\n\\n服务员笑了笑，说道：“非常抱歉，先生，我们的鱼菜单只供人类点餐。”\\n\\n猫眯起眼睛，微笑着说：“那没关系，我只要一条不会说话的鱼。”\\n\\n服务员无奈地笑了笑，点了一份鱼菜单放在猫面前。猫看了一眼菜单，然后把它推倒在地上。\\n\\n服务员惊讶地问：“为什么你这样做？”\\n\\n猫深情地看着服务员说：“因为我更喜欢鱼菜单的素材。”'),\n",
       "  'poem': AIMessage(content='软毛猫儿眯着眼，悠闲自在享宁静。\\n灵动身姿如舞蹈，温顺可爱似天使。')}]"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%time\n",
    "combined.batch([{\"topic\": \"熊\"}, {\"topic\": \"猫\"}])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchains",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
              